﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Configuration;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Principal;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.Security;
using System.Xml;
using TeamDoer.Helpers;
using TeamDoer.Models;

namespace TeamDoer.Controllers
{

	[HandleError]
	public class AccountController : BaseController
	{
		private readonly string TwitterConsumerKey = ConfigurationManager.AppSettings["TwitterConsumerKey"];
		private readonly string TwitterConsumerSecret = ConfigurationManager.AppSettings["TwitterConsumerSecret"];

		public IFormsAuthenticationService FormsService { get; set; }
		public AccountService UserAccountService { get; set; }

		protected override void Initialize(RequestContext requestContext)
		{
			if (FormsService == null) { FormsService = new FormsAuthenticationService(); }
			if (UserAccountService == null) { UserAccountService = new AccountService(); }

			base.Initialize(requestContext);
		}

		// **************************************
		// URL: /Account/LogOn
		// **************************************

		public ActionResult LogOn()
		{
			var model = new LogOnModel();
			return View(model);
		}

		private string GetFacebookUserJSON(string userid, string access_token)
		{
			string url = string.Format("https://graph.facebook.com/{0}?access_token={1}&fields=email,name,first_name,last_name,link", userid, access_token);

			WebClient wc = new WebClient();
			Stream data = wc.OpenRead(url);
			StreamReader reader = new StreamReader(data);
			string s = reader.ReadToEnd();
			data.Close();
			reader.Close();

			return s;
		}

		[HttpPost]
		public ActionResult LogOn(LogOnModel model, string returnUrl)
		{
			if (ModelState.IsValid)
			{
				if (UserAccountService.ValidateUser(model.UserName, model.Password))
				{
					FormsService.SignIn(model.UserName, model.RememberMe);
					return RedirectToAction("Index", "Tasks");
				}
				else
				{
					ModelState.AddModelError("", "The user name or password provided is incorrect.");
				}
			}

			// If we got this far, something failed, redisplay form
			return View(model);
		}

		[HttpGet]
		public ActionResult TwitterLogin()
		{
			oAuthTwitter oAuth = new oAuthTwitter();
			oAuth.ConsumerKey = TwitterConsumerKey;
			oAuth.ConsumerSecret = TwitterConsumerSecret;

			if (Request["oauth_token"] == null)
			{
				//Redirect the user to Twitter for authorization.
				//Using oauth_callback for local testing.
				oAuth.CallBackUrl = Request.Url.ToString();
				Response.Redirect(oAuth.AuthorizationLinkGet());
			}
			else
			{
				//Get the access token and secret.
				try
				{
					oAuth.AccessTokenGet(Request["oauth_token"], Request["oauth_verifier"]);
				}
				catch
				{
					ModelState.AddModelError("", "The user name or password provided is incorrect.");
					return View();
				}

				if (oAuth.TokenSecret.Length > 0)
				{
					//We now have the credentials, so make a call to the Twitter API.
					string url = "http://twitter.com/account/verify_credentials.xml";
					string xml = oAuth.oAuthWebRequest(oAuthTwitter.Method.GET, url, String.Empty);

					XmlDocument xmlDoc = new XmlDocument();
					xmlDoc.LoadXml(xml);
					TwitterUserInfo twitterUser = new TwitterUserInfo();
					twitterUser.twitterUsername = xmlDoc.GetElementsByTagName("screen_name")[0].InnerText;
					twitterUser.twitterHomepage = xmlDoc.GetElementsByTagName("url")[0].InnerText;
					twitterUser.twitterBio = xmlDoc.GetElementsByTagName("description")[0].InnerText;
					twitterUser.twitterImageURL = xmlDoc.GetElementsByTagName("profile_image_url")[0].InnerText;

					if (UserAccountService.GetUserIdByTwitterName(twitterUser.twitterUsername).HasValue)
					{
						FormsService.SignIn(twitterUser.twitterUsername, true);
						return RedirectToAction("Index", "Tasks");
					}
					else //we have to add a new user
					{
						ViewData["TwitterUser"] = twitterUser.twitterUsername;
						Session["TwitterUser"] = twitterUser;
						if (UserAccountService.GetUserIdByUserName(twitterUser.twitterUsername).HasValue) //user already exists, lets show "pick username"
						{
							ViewData["ShowPickName"] = true;
						}
					}
				}
			}
			return View();
		}

		[HttpPost]
		public ActionResult TwitterAddUser(FormCollection formCollection)
		{
			TwitterUserInfo twitterUser = (TwitterUserInfo)Session["TwitterUser"];

			string username = formCollection["newUserName"] ?? twitterUser.twitterUsername;

			UserAccountService.CreateUser(username, "1", formCollection["email"], "", "", twitterUser.twitterUsername);
			FormsService.SignIn(username, true);

			return RedirectToAction("Index", "Tasks");
		}

		[HttpGet]
		public ActionResult FacebookLogin()
		{
			if (Request.Cookies["fbs_" + ConfigurationManager.AppSettings["FacebookKey"]] == null) return View();

			string cookie = Request.Cookies["fbs_" + ConfigurationManager.AppSettings["FacebookKey"]].Value;
			cookie = cookie.Replace("\"", ""); //stupid Facebook bug
			NameValueCollection facebookValues = HttpUtility.ParseQueryString(cookie);

			string json = GetFacebookUserJSON(facebookValues["uid"], facebookValues["access_token"]);
			Hashtable jsonHash = (Hashtable)JSON.JsonDecode(json);

			string facebookName = jsonHash["name"] as string;
			string firstName = jsonHash["first_name"] as string;
			string lastName = jsonHash["last_name"] as string;
			string email = jsonHash["email"] as string;
			string facebookId = jsonHash["id"] as string;
			string url = jsonHash["link"] as string;

			string userName;
			int? userId = UserAccountService.GetUserIdByFacebookId(facebookId, out userName);

			//existing facebook user
			if (userId.HasValue)
			{
				FormsService.SignIn(userName, true);
				return RedirectToAction("Index", "Tasks");
			}
			else //no user yet, we have to add a new user
			{
				int? fbEmailUser = UserAccountService.GetUserIdByEmail(email); //if a user with this email already here
				if (fbEmailUser.HasValue) //lets set his fecaebookid
				{
					UserAccountService.SetUserFacebookId(fbEmailUser.Value, facebookId);
					userName = UserAccountService.GetUserNameById(fbEmailUser.Value);
					UserAccountService.UpdateUser(userName, email, firstName, lastName, null);
					FormsService.SignIn(userName, true);
					return RedirectToAction("Index", "Tasks");
				}
				else //creating a new user
				{
					UserAccountService.CreateUser(email, "1", email, firstName, lastName, "", facebookId);

					//todo: SetAvatarUrl(userId, string.Format("https://graph.facebook.com/{0}/picture", facebookId));

					FormsService.SignIn(email, true);
					return RedirectToAction("Index", "Tasks");
				}
			}
		}

		// **************************************
		// URL: /Account/LogOff
		// **************************************

		public ActionResult LogOff()
		{
			FormsService.SignOut();

			return RedirectToAction("Index", "Home");
		}

		// **************************************
		// URL: /Account/Register
		// **************************************

		public ActionResult Register()
		{
			ViewData["PasswordLength"] = AccountService.MinPasswordLength;
			return View();
		}

		[HttpPost]
		public ActionResult Register(RegisterModel model)
		{
			if (ModelState.IsValid)
			{
				// Attempt to register the user
				MembershipCreateStatus createStatus = UserAccountService.CreateUser(model.UserName, model.Password, model.Email, model.FirstName, model.LastName);

				if (createStatus == MembershipCreateStatus.Success)
				{
					FormsService.SignIn(model.UserName, false /* createPersistentCookie */);
					return RedirectToAction("Index", "Tasks");
				}
				else
				{
					ModelState.AddModelError("", AccountValidation.ErrorCodeToString(createStatus));
				}
			}

			// If we got this far, something failed, redisplay form
			ViewData["PasswordLength"] = AccountService.MinPasswordLength;
			return View(model);
		}

		// **************************************
		// URL: /Account/ChangePassword
		// **************************************

		[Authorize]
		public ActionResult ChangePassword()
		{
			ViewData["PasswordLength"] = AccountService.MinPasswordLength;
			return View();
		}

		protected override void Dispose(bool disposing)
		{
			base.Dispose(disposing);

			if (UserAccountService != null) UserAccountService.Dispose();
		}


		[Authorize]
		[HttpPost]
		public ActionResult ChangePassword(ChangePasswordModel model)
		{
			if (ModelState.IsValid)
			{
				if (UserAccountService.ChangePassword(User.Identity.Name, model.OldPassword, model.NewPassword))
				{
					return RedirectToAction("ChangePasswordSuccess");
				}
				else
				{
					ModelState.AddModelError("", "The current password is incorrect or the new password is invalid.");
				}
			}

			// If we got this far, something failed, redisplay form
			ViewData["PasswordLength"] = AccountService.MinPasswordLength;
			return View(model);
		}

		// **************************************
		// URL: /Account/ChangePasswordSuccess
		// **************************************

		public ActionResult ChangePasswordSuccess()
		{
			return View();
		}

		public ActionResult EditProfile()
		{
			EditProfileModel model = new EditProfileModel(User.Identity.Name);
			return View(model);
		}

		[HttpPost]
		public ActionResult EditProfile(EditProfileModel model)
		{
			if (ModelState.IsValid)
			{
				if (UserAccountService.UpdateUser(User.Identity.Name, model.Email, model.FirstName, model.LastName, model.TwitterName))
				{
					return RedirectToAction("EditProfileSuccess");
				}
				else
				{
					ModelState.AddModelError("", "Error saving profile. That email is already taken");
				}
			}

			return View(model);
		}

		public ActionResult EditProfileSuccess()
		{
			return View();
		}
	}
}
